/**
 * Created by zhoumingrui on 2017/1/16.
 */
var ObjMtlLoader = require("obj-mtl-loader");
var objMtlLoader = new ObjMtlLoader();
var ObjImgPrepare = require('../render/obj-img-prepare');

var objImgPrepare = new ObjImgPrepare();

class WavefrontObjLoader {
    constructor(options) {
        this.options = options || {}
        this.objMtlLoader = objMtlLoader;
        this.VSTEP = Float32Array.BYTES_PER_ELEMENT;
        this.ISTEP = Uint16Array.BYTES_PER_ELEMENT;
        this.TSTEP = Float32Array.BYTES_PER_ELEMENT;
        this.datas = [];
        this.drawArrays = [];
    }

    loadObj() {
        if (this.options.controller) {
            objMtlLoader.load("./obj/761.obj", "./obj/761.mtl", (err, result) => {
                if (err) {
                    /*Handle error here*/
                    console.log(err);
                    return;
                }
                this.createBuffer(result);
            });
        }
    }

    createBuffer(result) {
        let gl = this.options.controller.gl;
        if (!gl) return;
        objImgPrepare.saveMaterial(gl, result);
        // var vertices = result.vertices;
        // var faces = result.faces;
        // var normals = result.normals;
        // var textureCoords = result.textureCoords;
        // var facesMaterialsIndex = result.facesMaterialsIndex;
        // var materials = result.materials;

        let facesMaterialsIndex = result.facesMaterialsIndex;

        let verticesArray = [];
        for (let _vc = 0; _vc < result.vertices.length; _vc++) {
            verticesArray.push(result.vertices[_vc]);
        }
        let textureArray = [];
        for (let _tc = 0; _tc < result.textureCoords.length; _tc++) {
            textureArray.push(result.textureCoords[_tc]);
        }
        let normalArray = [];
        for (let _nc = 0; _nc < result.normals.length; _nc++) {
            normalArray.push(result.normals[_nc]);
        }
        /**
         * 归一数据
         */
        for (let _fc = 0; _fc < result.faces.length; _fc++) {
            let aFace = result.faces[_fc];

            let _indices = aFace.indices;
            let _normal = aFace.normal;
            let _texture = aFace.texture;
            /**
             * 先要把texture和vertices的对齐，normal线不对其了
             * indices:Array[3]
             * normal:Array[3]
             * texture:Array[3]
             */
            for (let _pair = 0; _pair < 3; _pair++) {
                let _texIndex = parseInt(_texture[_pair]) - 1;  //这里注意减一
                let _indIndex = parseInt(_indices[_pair]) - 1;  //这里注意减一
                let _nomIndex = parseInt(_normal[_pair]) - 1;  //这里注意减一
                normalArray[_indIndex] = result.normals[_nomIndex];
                if (_indices[_pair] != _texture[_pair]) {
                    textureArray[_indIndex] = result.textureCoords[_texIndex];
                }
            }
        }

        (function checkData() {
            for (let _ck = 0; _ck < normalArray.length; _ck++) {
                if (!normalArray[_ck]) normalArray[_ck] = [0, 0, 0];
                if(!textureArray[_ck]) textureArray[_ck] = [0,0];
            }
        }());

        /**
         * 填充索引
         */
        for (let i = 0; i < facesMaterialsIndex.length; i++) {
            let aMat = facesMaterialsIndex[i];
            /**
             * 先找faces,每个faces里包含
             */
            let subFaces = (i != facesMaterialsIndex.length - 1) ?
                result.faces.slice(aMat.materialStartIndex, facesMaterialsIndex[i + 1].materialStartIndex) :
                result.faces.slice(aMat.materialStartIndex);

            let _innerIndexArray = [];
            let _innerVerticesArray = [];
            let _innerTextureArray = [];
            let _innerNormalArray = [];

            for (let _f = 0; _f < subFaces.length; _f++) {
                let aFace = subFaces[_f];
                let _indices = aFace.indices;
                _innerIndexArray.push(parseInt(_indices[0]) - 1, parseInt(_indices[1]) - 1, parseInt(_indices[2]) - 1,);
            }
            /**
             * 查找最小的索引
             */
            let min = Math.min.apply(null, _innerIndexArray);
            let max = Math.max.apply(null, _innerIndexArray);
            /**
             * 先将数据填充到innerVertices和innerTextures
             */
            _innerVerticesArray = verticesArray.slice(min, max + 1);
            _innerTextureArray = textureArray.slice(min, max + 1);
            _innerNormalArray = normalArray.slice(min, max + 1);
            /**
             * 将索引里面的每一项都减少min
             */
            for (let _id = 0; _id < _innerIndexArray.length; _id++) {
                _innerIndexArray[_id] -= min;
            }
            /**
             * 写基本渲染单元
             * @type {{vertices: null, VB: null, textures: null, TB: null, indices: null, IB: null}}
             */
            let aUnit = {
                vertices: null,
                VB: null,
                textures: null,
                TB: null,
                indices: null,
                IB: null,
                normals: null,
                NB: null,
                materialName: aMat.materialName
            };

            aUnit.vertices = new Float32Array(this.extractData(_innerVerticesArray, 3));
            aUnit.textures = new Float32Array(this.extractData(_innerTextureArray, 2));
            aUnit.normals = new Float32Array(this.extractData(_innerNormalArray, 3));
            aUnit.indices = new Uint16Array(_innerIndexArray);

            aUnit.VB = gl.createBuffer();
            aUnit.TB = gl.createBuffer();
            aUnit.IB = gl.createBuffer();
            aUnit.NB = gl.createBuffer();

            gl.bindBuffer(gl.ARRAY_BUFFER, aUnit.VB);
            gl.bufferData(gl.ARRAY_BUFFER, aUnit.vertices, gl.STATIC_DRAW);

            gl.bindBuffer(gl.ARRAY_BUFFER, aUnit.TB);
            gl.bufferData(gl.ARRAY_BUFFER, aUnit.textures, gl.STATIC_DRAW);

            gl.bindBuffer(gl.ARRAY_BUFFER, aUnit.NB);
            gl.bufferData(gl.ARRAY_BUFFER, aUnit.normals, gl.STATIC_DRAW);

            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, aUnit.IB);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, aUnit.indices, gl.STATIC_DRAW);

            this.datas.push(aUnit);
        }

        this.rerender();
        this.options.controller.fire('vertices-load');
    }

    rerender() {
        let gl = this.options.controller.gl;
        if (!gl) return;

        for (let i = 0; i < this.datas.length; i++) {
            let aUnit = this.datas[i];

            objImgPrepare.bindOneImgById(gl, aUnit.materialName);

            gl.bindBuffer(gl.ARRAY_BUFFER, aUnit.VB);
            gl.vertexAttribPointer(gl.getAttribLocation(gl.program, "a_Position"), 3, gl.FLOAT, false, this.VSTEP * 3, 0);
            gl.enableVertexAttribArray(gl.getAttribLocation(gl.program, "a_Position"));

            gl.bindBuffer(gl.ARRAY_BUFFER, aUnit.TB);
            gl.vertexAttribPointer(gl.getAttribLocation(gl.program, "a_TexCoord"), 2, gl.FLOAT, false, this.TSTEP * 2, 0);
            gl.enableVertexAttribArray(gl.getAttribLocation(gl.program, "a_TexCoord"));

            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, aUnit.IB);

            gl.drawElements(gl.TRIANGLES, aUnit.indices.length, gl.UNSIGNED_SHORT, 0);
        }
    }

    extractData(arr, stride) {

        let outArray = [];
        for (let i = 0; i < arr.length; i++) {
            for (let j = 0; j < stride; j++) {
                outArray.push(arr[i][j]);
            }
        }
        return outArray;
    }

}

module.exports = WavefrontObjLoader;